﻿namespace Resharper.Abstractions.CodeDom.Expressions
{
  using System;
  using JetBrains.Annotations;
  using JetBrains.ReSharper.Psi.CSharp.Tree;
  using JetBrains.ReSharper.Psi.Tree;
  using Resharper.Abstractions.CodeDom.TreeNodes;

  /// <summary>Defines the <see cref="Expression"/> class.</summary>
  public class Expression : TreeNode
  {
    #region Constructors and Destructors

    /// <summary>Initializes a new instance of the <see cref="Expression"/> class.</summary>
    /// <param name="expression">The expression.</param>
    internal Expression([NotNull] IExpression expression) : base(expression)
    {
      if (expression == null)
      {
        throw new ArgumentNullException("expression");
      }

      this.InternalExpression = expression;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the constant value.
    /// </summary>
    [CanBeNull]
    public ConstantValue ConstantValue
    {
      get
      {
        var constantValue = this.InternalExpression.ConstantValue;

        return constantValue != null ? new ConstantValue(constantValue) : null;
      }
    }

    /// <summary>
    /// Gets a value indicating whether this instance is constant value.
    /// </summary>
    public bool IsConstantValue
    {
      get
      {
        return this.InternalExpression.IsConstantValue();
      }
    }

    /// <summary>
    /// Gets the type.
    /// </summary>
    [NotNull]
    public string TypeName
    {
      get
      {
        var type = this.InternalExpression.Type();

        return type.GetLongPresentableName(this.InternalExpression.Language);
      }
    }

    /// <summary>The expression field.</summary>
    [NotNull]
    protected internal IExpression InternalExpression { get; private set; }

    #endregion

    #region Public Methods

    /// <summary>Replaces the by.</summary>
    /// <param name="expression">The expression.</param>
    /// <returns>Returns the expression.</returns>
    [NotNull]
    public Expression ReplaceBy([NotNull] Expression expression)
    {
      if (expression == null)
      {
        throw new ArgumentNullException("expression");
      }

      var replace = (ICSharpExpression)this.InternalExpression;
      var with = (ICSharpExpression)expression.InternalExpression;

      var result = replace.ReplaceBy(with);

      return ExpressionFactory.GetExpression(result);
    }

    #endregion
  }
}